Step 31: Schema Validation
Let me remind you of the Bookmark schema:
import mongoose from "mongoose";
const BookmarkSchema = new mongoose.Schema({
  title: { type: String, required: true },
  url: { type: String, required: true },
});
const Bookmark = mongoose.model("Bookmark", BookmarkSchema);
export default Bookmark;
So what will happen if we make a bookmark and fail to provide a title? Let’s try it! Update the test in tests/mode/Bookmark.test.js and set title to null
test("test constructor", async () => {
  db.connect(process.env.DB_TEST_URI);
  const title = null;
  const url = faker.internet.url();
  const bookmark = await Bookmark.create({ title, url });
  expect(bookmark.title).toBe(title);
  expect(bookmark.url).toBe(url);
  expect(bookmark.id).toBeDefined();
  await Bookmark.deleteMany({});
});
Run this test. You should see a validation error generated by mongoose! By the way, you can provide more detailed error messages. Update src/model/Bookmark.js as follows:
import mongoose from "mongoose";
const BookmarkSchema = new mongoose.Schema({
  title: { type: String, required: [true, "Each bookmark must have a title"] },
  url: { type: String, required: [true, "Each bookmark must have a URL"] },
});
const Bookmark = mongoose.model("Bookmark", BookmarkSchema);
export default Bookmark;
We should test for erroneous inputs. Here is an example where we can do that.
test("test title is null", async () => {
  try {
    const title = null;
    const url = faker.internet.url();
    await Bookmark.create({ title, url });
  } catch (err) {
    expect(err).toBeDefined();
  }
});
Update tests/mode/Bookmark.test.js as follows to add various error handling tests:
import { describe, beforeAll, afterAll, expect, it } from "vitest";
import Bookmark from "../../src/model/Bookmark.js";
import { faker } from "@faker-js/faker";
import * as db from "../../src/data/db.js";
import * as dotenv from "dotenv";
dotenv.config();
describe("Test Bookmark Schema & Model", () => {
  beforeAll(async () => {
    db.connect(process.env.DB_TEST_URI);
    await Bookmark.deleteMany({});
  });
  it("test create bookmark", async () => {
    const title = faker.lorem.sentence();
    const url = faker.internet.url();
    const bookmark = await Bookmark.create({ title, url });
    expect(bookmark.title).toBe(title);
    expect(bookmark.url).toBe(url);
    expect(bookmark.id).toBeDefined();
  });
  describe("test title is required", () => {
    it("test title is null", async () => {
      try {
        const title = null;
        const url = faker.internet.url();
        await Bookmark.create({ title, url });
      } catch (err) {
        expect(err).toBeDefined();
      }
    });
    it("test title is undefined", async () => {
      try {
        const title = undefined;
        const url = faker.internet.url();
        await Bookmark.create({ title, url });
      } catch (err) {
        expect(err).toBeDefined();
      }
    });
    it("test title is empty", async () => {
      try {
        const title = "";
        const url = faker.internet.url();
        await Bookmark.create({ title, url });
      } catch (err) {
        expect(err).toBeDefined();
      }
    });
  });
  describe("test url is required", () => {
    it("test url is null", async () => {
      try {
        const title = faker.lorem.sentence();
        const url = "";
        await Bookmark.create({ title, url });
      } catch (err) {
        expect(err).toBeDefined();
      }
    });
    it("test url is undefined", async () => {
      try {
        const title = faker.lorem.sentence();
        const url = "";
        await Bookmark.create({ title, url });
      } catch (err) {
        expect(err).toBeDefined();
      }
    });
    it("test url is empty", async () => {
      try {
        const title = faker.lorem.sentence();
        const url = "";
        await Bookmark.create({ title, url });
      } catch (err) {
        expect(err).toBeDefined();
      }
    });
  });
  afterAll(async () => {
    await Bookmark.deleteMany({});
  });
});
Run the tests in this file and make sure they all pass. Then, save and commit changes.